home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / comms / other / slrn / slrn_src / src / sltcp.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  15KB  |  766 lines

  1. /* -*- mode: C; mode: fold; -*- */
  2. /* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
  3.  *
  4.  * This file is part of slrn.
  5.  *
  6.  * Slrn is free software; you can redistribute it and/or modify it
  7.  * under the terms of the GNU General Public License as published by the
  8.  * Free Software Foundation; either version 2, or (at your option) any
  9.  * later version.
  10.  * 
  11.  * Slrn is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with Slrn; see the file COPYING.  If not, write to the Free
  18.  * Software Foundation, 59 Temple Place - Suite 330, 
  19.  * Boston, MA  02111-1307, USA.
  20.  */
  21.  
  22. #include "config.h"
  23.  
  24. /*{{{ Include Files */
  25.  
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31.  
  32. #include <errno.h>
  33. #include <ctype.h>
  34. #include <stdarg.h>
  35.  
  36. #include <setjmp.h>
  37. #include <signal.h>
  38.  
  39. #include <sys/types.h>
  40.  
  41. #ifdef HAVE_SOCKET_H
  42. # include <socket.h>
  43. #endif
  44.  
  45. #ifdef HAVE_SYS_SOCKET_H
  46. # include <sys/socket.h>
  47. #endif
  48.  
  49. #if defined(__NT__) 
  50. # include <winsock.h>
  51. # define USE_WINSOCK_SLTCP    1
  52. #else
  53. # if defined(__MINGW32__)
  54. #  define Win32_Winsock
  55. #  include <windows.h>
  56. #  define USE_WINSOCK_SLTCP    1
  57. # endif
  58. #endif
  59.  
  60. #ifdef USE_WINSOCK_SLTCP
  61. # define USE_WINSOCK_SLTCP    1
  62. #else
  63. # include <netdb.h>
  64. #endif
  65.  
  66.  
  67. #ifdef HAVE_NETINET_IN_H
  68. # include <netinet/in.h>
  69. #endif
  70.  
  71. #ifdef HAVE_ARPA_INET_H
  72. # include <arpa/inet.h>
  73. #endif
  74.  
  75. #ifndef h_errno
  76. extern int h_errno;
  77. #endif
  78.  
  79. /* For select system call */
  80. #ifdef VMS
  81. # include <unixio.h>
  82. # include <socket.h>
  83. # include <in.h>
  84. # include <inet.h>
  85. #else
  86. # if !defined(USE_WINSOCK_SLTCP)
  87. #  include <sys/time.h>
  88. # endif
  89. # if defined(__QNX__) || defined(__os2__)
  90. #  include <sys/select.h>
  91. # endif
  92. # if defined (_AIX) && !defined (FD_SET)
  93. #  include <sys/select.h>    /* for FD_ISSET, FD_SET, FD_ZERO */
  94. # endif
  95.  
  96. # ifndef FD_SET
  97. #  define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
  98. #  define FD_ZERO(tthis)    *(tthis) = 0
  99. #  define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
  100.  typedef int fd_set;
  101. # endif
  102. #endif
  103.  
  104. #include <slang.h>
  105.  
  106. #include "sltcp.h"
  107.  
  108. /*}}}*/
  109.  
  110. #if defined(__BEOS__) || defined(USE_WINSOCK_SLTCP)
  111. # define SLTCP_CLOSE(x)        closesocket(x)
  112. # define SLTCP_READ(x,y,z)    recv((x),(y),(z),0)
  113. # define SLTCP_WRITE(x,y,z)    send((x),(y),(z),0)
  114. #else
  115. # define SLTCP_CLOSE(x)        close(x)
  116. # define SLTCP_READ(x,y,z)    read((x),(y),(z))
  117. # define SLTCP_WRITE(x,y,z)    write((x),(y),(z))
  118. #endif
  119.  
  120. int (*SLTCP_Interrupt_Hook) (void);
  121. int SLtcp_TimeOut_Secs = 120;
  122.  
  123. static int TCP_Verbose_Reporting = 0;
  124.  
  125. static int sys_call_interrupted_hook (void) /*{{{*/
  126. {
  127.    if (SLTCP_Interrupt_Hook == NULL)
  128.      return 0;
  129.    
  130.    return (*SLTCP_Interrupt_Hook) ();
  131. }
  132.  
  133. /*}}}*/
  134.  
  135.  
  136. /* This function attempts to make a connection to a specified port on an
  137.  * internet host.  It returns a socket descriptor upon success or -1
  138.  * upon failure.
  139.  */
  140. static int get_tcp_socket_1 (char *host, int port) /*{{{*/
  141. {
  142.    char **h_addr_list;
  143.    /* h_addr_list is NULL terminated if h_addr is defined.  If h_addr
  144.     * is not defined, h_addr is the only element in the list.  When
  145.     * h_addr is defined, its value is h_addr_list[0].
  146.     */
  147.    int h_length;
  148.    int h_addr_type;
  149.    char *fake_h_addr_list[2];
  150.    unsigned long fake_addr;
  151.    struct sockaddr_in s_in;
  152.    int s;
  153.    int not_connected;
  154.  
  155.    /* If it does not look like a numerical address, use nameserver */
  156.    if (!isdigit(*host) || (-1L == (long)(fake_addr = inet_addr (host))))
  157.      {
  158.     struct hostent *hp;
  159.     unsigned int max_retries = 3;
  160.     
  161.     while (NULL == (hp = gethostbyname (host)))
  162.       {
  163. #ifdef TRY_AGAIN
  164.          max_retries--;
  165.          if (max_retries && (h_errno == TRY_AGAIN))
  166.            {
  167.           sleep (1);
  168.           continue;
  169.            }
  170. #endif
  171.          fprintf(stderr, "%s: Unknown host.\n", host);
  172.          return -1;
  173.       }
  174.     
  175. #ifdef h_addr
  176.     h_addr_list = hp->h_addr_list;
  177. #else
  178.     h_addr_list = fake_h_addr_list;
  179.     h_addr_list [0] = hp->h_addr;
  180.     h_addr_list [1] = NULL;
  181. #endif
  182.     h_length = hp->h_length;
  183.     h_addr_type = hp->h_addrtype;
  184.      }
  185.    else 
  186.      {
  187.     h_addr_list = fake_h_addr_list;
  188.     h_addr_list [0] = (char *) &fake_addr;
  189.     h_addr_list [1] = NULL;
  190.     
  191.     h_length = sizeof(struct in_addr);
  192.     h_addr_type = AF_INET;
  193.      }
  194.  
  195.    memset ((char *) &s_in, 0, sizeof(s_in));
  196.    s_in.sin_family = h_addr_type;
  197.    s_in.sin_port = htons((unsigned short) port);
  198.  
  199.    if (-1 == (s = socket (h_addr_type, SOCK_STREAM, 0)))
  200.      {
  201.     perror("socket");
  202.     return -1;
  203.      }
  204.     
  205.    not_connected = -1;
  206.    
  207.    while (not_connected 
  208.       && (h_addr_list != NULL) 
  209.       && (*h_addr_list != NULL))
  210.      {
  211.     char *this_host;
  212.     
  213.     memcpy ((char *) &s_in.sin_addr, *h_addr_list, h_length);
  214.  
  215.     this_host = (char *) inet_ntoa (s_in.sin_addr);
  216.     
  217.     if (TCP_Verbose_Reporting) fprintf (stderr, "trying %s\n", this_host);
  218.     
  219.     not_connected = connect (s, (struct sockaddr *)&s_in, sizeof (s_in));
  220.     
  221.     if (not_connected == -1)
  222.       {
  223. #ifdef EINTR
  224.          if (errno == EINTR) /* If interrupted, try again. */
  225.            {
  226.           if (0 == sys_call_interrupted_hook ())
  227.             continue;
  228.            }
  229. #endif
  230.          fprintf (stderr, "connection to %s, port %d:", 
  231.               (char *) this_host, port);
  232.          perror ("");
  233.       }
  234.     h_addr_list++;
  235.      }
  236.    
  237.    if (not_connected) 
  238.      {
  239.     fprintf(stderr, "Unable to make connection. Giving up.\n");
  240.     (void) SLTCP_CLOSE (s);
  241.     return -1;
  242.      }
  243.    return s;
  244. }
  245.  
  246. /*}}}*/
  247.  
  248. #if HAVE_SIGLONGJMP
  249. /*{{{ get_tcp_socket routines with sigsetjmp/siglongjmp */
  250.  
  251. static void restore_sigint_handler (void (*f)(int), int call_it) /*{{{*/
  252. {
  253.    if (f == SIG_ERR)
  254.      return;
  255.    
  256.    (void) SLsignal_intr (SIGINT, f);
  257.  
  258.    if (call_it)
  259.      kill (getpid (), SIGINT);
  260. }
  261.  
  262. /*}}}*/
  263.  
  264.    
  265. static sigjmp_buf Sigint_Jmp_Buf;
  266.  
  267. static void (*Old_Sigint_Handler) (int);
  268. static volatile int Jump_In_Progress;
  269.  
  270. static void sigint_handler (int sig) /*{{{*/
  271. {
  272.    (void) sig;
  273.    
  274.    if (Jump_In_Progress) return;
  275.    Jump_In_Progress = 1;
  276.  
  277.    siglongjmp (Sigint_Jmp_Buf, 1);
  278. }
  279.  
  280. /*}}}*/
  281.  
  282. static int get_tcp_socket (char *host, int port) /*{{{*/
  283. {
  284.    int fd;
  285.  
  286.    Old_Sigint_Handler = SIG_ERR;
  287.    
  288.    Jump_In_Progress = 1;           /* dont allow jump yet */
  289.    if (0 != sigsetjmp (Sigint_Jmp_Buf, 1))   /* save signal mask */
  290.      {
  291.     restore_sigint_handler (Old_Sigint_Handler, 1);
  292.     sys_call_interrupted_hook ();
  293.     return -1;
  294.      }
  295.    
  296.    Old_Sigint_Handler = SLsignal_intr (SIGINT, sigint_handler);
  297.    
  298.    if ((Old_Sigint_Handler == SIG_IGN) 
  299.        || (Old_Sigint_Handler == SIG_DFL))
  300.      {
  301.     restore_sigint_handler (Old_Sigint_Handler, 0);
  302.     Old_Sigint_Handler = SIG_ERR;
  303.      }
  304.    
  305.    Jump_In_Progress = 0;           /* now allow the jump */
  306.    fd = get_tcp_socket_1 (host, port);
  307.    Jump_In_Progress = 1;           /* don't allow jump */
  308.    
  309.    restore_sigint_handler (Old_Sigint_Handler, 0);
  310.    
  311.    return fd;
  312. }
  313.  
  314. /*}}}*/
  315.  
  316. /*}}}*/
  317. #else
  318. static int get_tcp_socket (char *host, int port) /*{{{*/
  319. {
  320.    return get_tcp_socket_1 (host, port);
  321. }
  322.  
  323. /*}}}*/
  324. #endif                          /* HAVE_SIGLONGJMP */
  325.        
  326. SLTCP_Type *sltcp_open_connection (char *host, int port) /*{{{*/
  327. {
  328.    int fd;
  329.    SLTCP_Type *tcp;
  330.    
  331.    tcp = (SLTCP_Type *) SLMALLOC (sizeof (SLTCP_Type));
  332.    if (tcp == NULL)
  333.      {
  334.     fprintf (stderr, "Memory Allocation Failure.\n");
  335.     return NULL;
  336.      }
  337.    memset ((char *) tcp, 0, sizeof (SLTCP_Type));
  338.    
  339.    tcp->tcp_fd = -1;
  340.    tcp->tcp_read_ptr = tcp->tcp_read_ptr_max = tcp->tcp_read_buf;
  341.    tcp->tcp_write_ptr = tcp->tcp_write_ptr_min = tcp->tcp_write_buf;
  342.    
  343.    fd = get_tcp_socket (host, port);
  344.    if (fd == -1) 
  345.      {
  346.     SLFREE (tcp);
  347.     return NULL;
  348.      }
  349.  
  350.    tcp->tcp_fd = fd;
  351.    
  352.    return tcp;
  353. }
  354.  
  355. /*}}}*/
  356.  
  357. static unsigned int do_write (SLTCP_Type *tcp, unsigned char *buf, unsigned int len) /*{{{*/
  358. {
  359.    unsigned int total;
  360.    int nwrite;
  361.    int fd;
  362.    
  363.    total = 0;
  364.    fd = tcp->tcp_fd;
  365.    
  366.    while (total != len)
  367.      {
  368.     nwrite = SLTCP_WRITE (fd, (char *) buf, (len - total));
  369.     
  370.     if (nwrite == -1)
  371.       {
  372. #ifdef EAGAIN
  373.          if (errno == EAGAIN) 
  374.            {
  375.           sleep (1);
  376.           continue;
  377.            }
  378. #endif
  379. #ifdef EWOULDBLOCK
  380.          if (errno == EWOULDBLOCK)
  381.            {
  382.           sleep (1);
  383.           continue;
  384.            }
  385. #endif
  386. #ifdef EINTR
  387.          if (errno == EINTR) 
  388.